/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 * NuGat-API named Chameleon developed by Simon De Baets to Verimag.
 *
 */


package chameleon.model.NuGatStructure.symbTable;

import chameleon.model.NuGatStructure.utils.NodeList;
import chameleon.model.NuGatStructure.utils.Node;
import chameleon.model.NuGatStructure.enc.BoolEnc;
import chameleon.model.NuGatStructure.enc.BddEnc;
import chameleon.gameSolver.NuGat.NuGatInterface;
import chameleon.model.NuGatStructure.NuGatStructure;
import com.sun.jna.Pointer;

/**
 * This class is a wrapper to the C struct symbTable.c
 *
 * @author simon
 */
public class SymbTable extends NuGatStructure {

    BddEnc bddEnc_;
    BoolEnc boolEnc_;
    
    public SymbTable (Pointer symbTable, BddEnc bddEnc, BoolEnc boolEnc, NuGatInterface nugat){
        super (symbTable,nugat);
        bddEnc_ = bddEnc;
        boolEnc_ = boolEnc;
    }

    /**
     * Return the layer corresponding to the name.
     *
     * @param layer_name
     * @return SymbLayer_ptr
     */

    public SymbLayer getLayer(String layer_name){
        return new SymbLayer(nugat_.SymbTable_get_layer(this.ptr(), layer_name), nugat_) ;
    }

    public void removeLayer (String layer_name){
        nugat_.SymbTable_remove_layer(this.ptr(), getLayer(layer_name).ptr());
    }
    
    /**
     * Return the variables.
     *
     * @return NodeList_ptr
     */

    public NodeList getVars (){
        return new NodeList(nugat_.SymbTable_get_vars(this.ptr()),nugat_);
    }
    
    /**
     * Create a new layer
     * @param layer_name
     * @param LayerInsertPolicy_ins_policy
     * @return 
     */
    
    public SymbLayer createLayer(String layer_name,
                                     int LayerInsertPolicy_ins_policy){
        return new SymbLayer(nugat_.SymbTable_create_layer(this.ptr(),
                layer_name, LayerInsertPolicy_ins_policy), nugat_);
    }

    
    /**
     * WARNING : not Functional yet, committing must be use after
     * 
     * This function add a new state bound integer value to the layer of one player.
     * 
     * see : compile_instantiate_var, compile_instantiate_vars
     * 
     * @param name
     * @param player
     * @param lowerBound
     * @param upperBound 
     * @return SymbLayer
     */    
    public void addIntVariable(String name, int player, int lowerBound, int upperBound){
        
        SymbLayer layer = null;
        Node values;
        SymbType symbolicType;
        
        /*if (player==1)
            layer = getLayer(nugat_.LAYER_PLAYER_1);
        else if (player==2)
            getLayer(nugat_.LAYER_PLAYER_2);
        else
            throw new RuntimeException("AddVariable :: Only two players game are supported!");*/
        
        layer = getLayer("test");
        
        Node var = createVarNode(name);
        
        //check if the name is free
        if (!layer.canDeclareVar(var))
            throw new RuntimeException(name+" is not a free name");
        
        
        /* Create a list of values. */
        values = new Node(nugat_.CompileFlatten_expand_range(lowerBound, upperBound),
                  nugat_);
        /* We don't declare constants here since there are just numbers. */
        symbolicType = new SymbType(nugat_.SYMB_TYPE_ENUM, values,nugat_);
        layer.declareStateVar(var, symbolicType);
        
    }
    
    /**
     * Create a node that represent the varName .
     * @param varName
     * @return Node
     */
    
    private Node createVarNode(String varName){
        Node var = new Node(Pointer.NULL,nugat_);
        var = var.findNode(nugat_.ATOM, nugat_.find_string(varName),
                        Pointer.NULL);
        var = var.findNode(nugat_.DOT, Pointer.NULL, var.ptr());
        return var;
    }

    public void commitLayer(SymbLayer layer){
        boolEnc_.commitLayer(layer);
        bddEnc_.commitLayer(layer);
    }
    
    public void removeLayer(SymbLayer layer){
        boolEnc_.removeLayer(layer);
        bddEnc_.removeLayer(layer);
    }

    public NodeList getLayersSfIVars (Pointer layers){
        return new NodeList(nugat_.SymbTable_get_layers_sf_i_vars(this.ptr(), layers), nugat_);
    }
}
